﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace LayeredArchitectureSample.DomainModel
{
    [GenerateDataTransferObject(TemplateName = "DefaultDtoTemplate.tt")]
    public class Route : DomainObject
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="waypoints"></param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentException"></exception>
        public Route(long id, IEnumerable<Location> waypoints) : base(id)
        {
            if (waypoints == null) throw new ArgumentNullException("waypoints");

            Location previousLocation = null;
            
            foreach (Location waypoint in waypoints)
            {
                if (waypoint == null)
                {
                    throw new ArgumentException("Nulls are not allowed as waypoints");
                }

                if (previousLocation != null)
                {
                    if (waypoint.Equals(previousLocation))
                    {
                        throw new ArgumentException("Cannot have two same locations appearing twice in a row in a route", "waypoints");
                    }
                }

                previousLocation = waypoint;
            }

            Waypoints = new List<Location>(waypoints).AsReadOnly();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="locations"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public bool DoWaypointsMatch(IEnumerable<Location> locations)
        {
            if (locations == null) throw new ArgumentNullException("locations");

            var route1Enumerator = Waypoints.GetEnumerator();
            var route2Enumerator = locations.GetEnumerator();

            while (route1Enumerator.MoveNext())
            {
                if (!route2Enumerator.MoveNext())
                {
                    return false;
                }

                if (route1Enumerator.Current == null || route2Enumerator.Current == null)
                {
                    throw new ArgumentException("Nulls are not allowed as waypoints");
                }

                if (!route1Enumerator.Current.Equals(route2Enumerator.Current))
                {
                    return false;
                }
            }

            // route2 can be longer, no match in this case
            return !route2Enumerator.MoveNext();
        }

        public ReadOnlyCollection<Location> Waypoints { get; private set; }

        public bool Equals(Route other)
        {
            return base.Equals(other);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            return Equals(obj as Route);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}